package com.md.util;

import com.md.model.base.ColorInfo;
import lombok.experimental.UtilityClass;

import static com.md.value.ColorConstants.BLUE_ADJUSTMENT_FACTOR;
import static com.md.value.ColorConstants.COLOR_RANG;
import static com.md.value.ColorConstants.COLOR_RANG_EQUIPARTITION_POINT;
import static com.md.value.ColorConstants.GRAY_RANG;
import static com.md.value.ColorConstants.GREEN_ADJUSTMENT_FACTOR;
import static com.md.value.ColorConstants.HEX_MAX;
import static com.md.value.ColorConstants.MAX_RGB;
import static com.md.value.ColorConstants.ORANGE_TO_YELLOW;
import static com.md.value.ColorConstants.RED_TO_ORANGE;
import static com.md.value.ColorConstants.YELLOW_TO_GREEN;
import static com.md.value.ReadFileConstants.COLOR_SUB_START_INDEX;
import static com.md.value.ReadFileConstants.HEX;
import static com.md.value.ReadFileConstants.MAX_RGB_BYTE_ARRAY_LENGTH;

/**
 * @author 刘骄阳
 * 2024-06-05 12:00
 */
@UtilityClass
public class ColorUtil {
  /**
   * 将byte转为double
   *
   * @param rgb rgb范围
   * @return double
   */
  public static double convertRGBByteToDouble(final byte rgb) {
    return rgb & HEX_MAX;
  }

  /**
   * 将RGB颜色值转换为HSL颜色值。
   * RGB颜色模型是一种加性颜色混合模型，用于电子设备如电视和计算机显示器的颜色表示。
   * HSL颜色模型是一种用于表示颜色的模型，其中H代表色相，S代表饱和度，L代表亮度。
   *
   * @param r 红色通道的值，范围为0-255。
   * @param g 绿色通道的值，范围为0-255。
   * @param b 蓝色通道的值，范围为0-255。
   * @return 包含HSL值的数组，顺序为色相、饱和度、亮度。
   */
  public static double[] convertRGBToHSL(final byte r, final byte g, final byte b) {
    // 将RGB值转换为0-1范围内的double值
    double doubleRed = (convertRGBByteToDouble(r) / MAX_RGB);
    double doubleGreen = (convertRGBByteToDouble(g) / MAX_RGB);
    double doubleBlue = (convertRGBByteToDouble(b) / MAX_RGB);

    // 找出色值的最大值和最小值，用于计算亮度和饱和度
    double max = Math.max(doubleRed, Math.max(doubleGreen, doubleBlue));
    double min = Math.min(doubleRed, Math.min(doubleGreen, doubleBlue));

    // 计算亮度
    double lightness = (max + min) / 2.0;

    // 初始化色相和饱和度
    double hue;
    double saturation;

    // 如果最大值和最小值相等，说明是灰阶色，色相和饱和度都为0
    if (max == min) {
      hue = 0;
      saturation = 0;
    } else {

      // 计算饱和度
      double d = max - min;
      if (lightness > GRAY_RANG) {
        saturation = d / (2.0 - max - min);
      } else {
        saturation = d / (max + min);
      }
      // 根据最大值和最小值的比较，计算色相
      if (max == doubleRed) {
        if (doubleGreen < doubleBlue) {
          hue = (doubleGreen - doubleBlue) / d + COLOR_RANG.length;
        } else {
          hue = (doubleGreen - doubleBlue) / d;
        }
      } else if (max == doubleGreen) {
        hue = (doubleBlue - doubleRed) / d + GREEN_ADJUSTMENT_FACTOR;
      } else {
        hue = (doubleRed - doubleGreen) / d + BLUE_ADJUSTMENT_FACTOR;
      }
      // 将色相值标准化到0-360的范围
      hue /= COLOR_RANG.length;
    }
    return new double[]{hue, saturation, lightness};
  }

  /**
   * HSL转RGB
   *
   * @param h 色相, 范围为0到1。
   * @param s 饱和度, 范围为0到1。
   * @param l 明度, 范围为0到1。
   * @return RGB颜色字符串形式，如 "rgb(255, 127, 0)"。
   */
  public static String convertHSLToRGB(final double h, final double s, final double l) {
    double r;
    double g;
    double b;
    if (s == 0) {
      r = l;
      g = l;
      b = l;
    } else {

      double q;
      if (l < GRAY_RANG) {
        q = l * (1 + s);
      } else {
        q = l + s - l * s;
      }

      double p = 2 * l - q;

      r = hue2rgb(p, q, h + COLOR_RANG_EQUIPARTITION_POINT);
      g = hue2rgb(p, q, h);
      b = hue2rgb(p, q, h - COLOR_RANG_EQUIPARTITION_POINT);
    }
    int red = (int) Math.round(r * MAX_RGB);
    int green = (int) Math.round(g * MAX_RGB);
    int blue = (int) Math.round(b * MAX_RGB);

    return String.format("rgb(%d, %d, %d)", red, green, blue);
  }

  private static double hue2rgb(final double p, final double q, final double t) {
    double t1 = t;
    if (t1 < 0) {
      t1++;
    }
    if (t1 > 1) {
      t1--;
    }
    // 根据t在色相轮中的位置段计算RGB分量。
    // 色相环被分为六个等份，每个等份代表一个基本颜色（红、橙、黄、绿、青、蓝）及其过渡色。
    //1.0 / 6 和 2.0 / 3 分别代表这些等份的起点和终点。
    if (t1 < RED_TO_ORANGE) {
      // 第一段，使用线性插值计算
      return p + (q - p) * COLOR_RANG.length * t1;
    }
    if (t1 < ORANGE_TO_YELLOW) {
      // 当 t1 在第二段（1/6到1/2）时，直接返回 q，因为此时色相处于最饱和状态，即基本颜色本身。
      return q;
    }
    if (t1 < YELLOW_TO_GREEN) {
      // 第三段，再次使用线性插值计算
      return p + (q - p) * (YELLOW_TO_GREEN - t1) * COLOR_RANG.length;
    }
    // 当 t1 超过2/3时，返回 p，表示色相又回到了起点，完成一圈的计算
    return p;
  }

  /**
   * 颜色
   *
   * @return 颜色
   */
  public static <T extends ColorInfo> T getBlackColorInfo(final Class<T> clazz) {
    T t;
    try {
      t = clazz.newInstance();
      if (t != null) {
        t.setRgb(new byte[]{0, 0, 0});
      }
    } catch (InstantiationException | IllegalAccessException e) {
      return null;
    }
    return t;
  }

  private static byte[] convertHexToByteArray(final String hexColor) {
    if (ObjectUtil.isEmpty(hexColor)) {
      return new byte[]{0, 0, 0};
    }
    String hexColorTrim = hexColor.trim();
    // 将每一对16进制数字转换为字节
    byte[] bytes = new byte[MAX_RGB_BYTE_ARRAY_LENGTH];

    for (int i = 0; i < MAX_RGB_BYTE_ARRAY_LENGTH; i++) {
      bytes[i] = (byte) Integer.parseInt(hexColorTrim.substring(i * 2, i * 2 + 2), HEX);
    }
    return bytes;
  }

  private static byte[] convertRGBToByteArray(final String hexColor) {
    if (ObjectUtil.isEmpty(hexColor)) {
      return new byte[]{0, 0, 0};
    }
    String hexColorTrim = hexColor.trim();
    byte[] bytes = new byte[MAX_RGB_BYTE_ARRAY_LENGTH];
    String[] colorByte = hexColorTrim.split(",");
    int colorByteLength = colorByte.length;
    for (int i = 0; i < colorByteLength; i++) {
      bytes[i] = (byte) Double.parseDouble(colorByte[i].trim());
    }
    return bytes;
  }

  public static byte[] convertToByteArray(final String hexColor) {
    if (ObjectUtil.isEmpty(hexColor)) {
      return new byte[]{0, 0, 0};
    }
    String hexColorTrim = hexColor.trim();
    if (hexColorTrim.startsWith("rgb")) {
      return convertRGBToByteArray(hexColorTrim.substring(COLOR_SUB_START_INDEX, hexColorTrim.length() - 1));
    }
    if (hexColorTrim.startsWith("#")) {
      return convertHexToByteArray(hexColorTrim.substring(1));
    }
    return convertHexToByteArray(hexColorTrim);
  }
}
